<?php 
 /**
  * 数据库模型基础类
  *   
  * @author wenqiang@6rooms.com
  * @version $Id: Base.class.php,v 1.0 2013/11/28 17:08:30 gaowenqiang Exp $   
  * @package hw.model   
  *
  */
class Hw_Model_Base 
{
	/**
	 * 数据库对象
	 * @var DBHelperi_applepie
	 *
	 */
	protected $db; 

	/**
	 * 表名
	 * @var string
	 *
	 */
	protected $name; 

	/**
	 * 主键名
	 * @var string
	 *
	 */
	protected $primary;
	
	/**
	 * 计算列表达式
	 * @var array
	 *
	 */
	protected $expr = array();

	/**
	 * Constructor
	 *
	 * @param array @args 配置参数
	 * @return void
	 *
	 */
	public function __construct($args = null)
	{
		$this->setup($args);
	} 

	/**
	 * 装配模型
	 * 
	 * @param array $args 参数, env,db可二选一, env优先
	 *   'env' string 数据环境变量(DEV/PRO)
	 *   'db'  object(DBHelperi_applepie) 数据库对象
	 * @return void 
	 */
	public function setup($args = null)
	{
		if (is_array($args) && !empty($args)) {
			if (isset($args['env'])) {
				$this->setDb($this->getDefaultDb($args['env']));
			} elseif (isset($args['db'])) {
				$this->setDb($args['db']);
			} else {
				// ...
			} 
		} 
	}

	/**
	 * 设置DB对象
	 * 
	 * @param  Object $db 数据库对象(DBHelperi_applepie)
	 * @return void 
	 */
	public function setDb($db = null)
	{
		if ($db) {
			$this->db = $db;
		} else {
			/**
			 * if (!$this->db) {
			 * $default['env'] = 'DEV';// 数据连接默认连接环境
			 * $this->db = $this->getDefaultDb($default['env']);
			 * }
			 */
		} 
	} 

	/**
	 * 获取表名
	 * 
	 * @return string 
	 */
	public function getName($name = null)
	{
		return !is_null($name) ? $name : $this->name;
	} 

	/**
	 * 根据主键查询一条数据
	 * 
	 * @param int $id 编号
	 * @return array 
	 */
	public function load($primaryValue, $table = null)
	{
		if (!$primaryValue) {
			return false;
		} 
		
		$table = $this->getName($table);

		$sql = "SELECT * FROM {$table} WHERE {$this->primary} = {$primaryValue}";

		$row = $this->fetchRow($sql);
		return $row;
	} 

	/**
	 * 插入数据(单条/多条)
	 * 
	 * @param  array $values 数据
	 * @param  string $table 表名
	 * @return void 
	 */
	public function insert($values, $table = null)
	{
		$table = $this->getName($table);

		return self::inserts($this->db, $table, $values);
	}

	/**
	 * 更新数据(单条)
	 * 
	 * @param  array $data 数据
	 * @param  string $where 条件
	 * @param  string $table 表名
	 * @return bool 
	 */
	public function update($data, $where = null, $table = null)
	{
		$table = $this->getName($table);
		$limit = array('size' => 1);
		return self::updates($this->db, $table, $data, $where, $limit);
	} 

	/**
	 * 删除数据(单条)
	 *
	 * @param  string $where 条件
	 * @param  string $table 表名
	 * @return bool 
	 */
	public function delete($where, $table = null)
	{
		$table = $this->getName($table);
		$limit = array('size' => 1);
		return self::deletes($this->db, $table, $where, $limit);
	}
	
	// modify 2013年12月3日 18:21:59 此处cols是否必填需再考虑 ？？？？？？？？
	/**
	 * 从文件中导入数据
	 * 
	 * @param string $filename 数据文件名(目前是CSV格式, 其它有时间再改)
	 * @param string $cols 列名
	 * @param string $table 表名
	 * @return bool 
	 */
	public function import($filename, $cols = null, $table = null)
	{
		$table = $this->getName($table);
		self::importByFile($this->db, $table, $filename, $cols, true);
	}

	/**
	 * 获取首行首列
	 * 
	 * @param string $where 查询条件字符串
	 * @param string $col 查询列
	 * @return string
	 */
	public function fetchOne($where, $col, $table = null)
	{
		$table = $this->getName($table);

		$sql = "SELECT {$col} FROM {$table} WHERE {$where}";
		$row = $this->fetchRow($sql);
		return $row && isset($row[0]) ? $row[0] : null;
	} 

	/**
	 * 获取一条数据
	 * 
	 * @param string $sql 查询语句
	 * @return array 
	 */
	public function fetchRow($sql)
	{
		$limit = $this->limit(array('size' => 1, 'offset' => 0));
		$sql .= " {$limit}";

		$row = array();
		$result = $this->db->query($sql);
		if ($result) {
			$row = $result->fetch_array();
		} 
		return $row;
	}

	/**
	 * 获取查询结果的全部数据
	 * 
	 * @param string $sql 
	 * @return array 
	 */
	public function fetchAll($sql)
	{
		$rows = array();

		$result = $this->db->query($sql);
		if ($result) {
			while ($row = mysqli_fetch_assoc($result)) {
				$rows[] = $row;
			} 
		} 
		return $rows;
	}

	public function fetchAssoc($sql)
	{
		$rows = array();

		$result = $this->db->query($sql);
		if ($result) {
			while ($row = mysqli_fetch_assoc($result)) {
				$tmp = array_values(array_slice($row, 0, 1));
				$rows[$tmp[0]] = $row;
			} 
		} 
		return $rows;
	}
	
	/**
	 * 获取键值对数组数据
	 *
	 * @param string $sql
	 * @param array $columns 
	 *
	 */
	public function fetchPairs($sql, $keyName, $valName = null) 
	{
		$keyField = $valField = null;
		if (!(strlen($keyName) && strlen($valName))) {
			return false;
		} else {
			$tmp = strlen($keyName) ? $keyName : $valName;
			$keyField = $tmp;
			$valField = $tmp;
		}

		$rows = array();
		$data = $this->fetchAll($sql);
		if ($data) {
			foreach ($data as $row) {
				$rows[$row[$keyField]] = $row[$valField];
			}
		}
		return $rows;
	}
	
	/**
	 * 生成列
	 *
	 * @param mixed array|string 列数据
	 * @param bool $toString 是否转换为字符串
	 * @return mixed array|string
	 *
	 */
	protected function column($columnData, $toString = true)
	{
		
		$columnParams = null;
		if (is_string($columnData)) {// 字符串转为数组
			$columnParams = array($columnData);
		} elseif (is_array($columnData) && !empty($columnData)) {
			$columnParams = $columnData;
		} else {
			return null;
		}

		$columns = array();
		foreach ($columnParams as $key => $val) {
			if (is_int($key)) {// 无别名
				$tmpKey = strtoupper($val);
				if (isset($this->expr[$tmpKey])) {
					// 属内部表达式, 默认别名
					$columns[] = $this->expr[$tmpKey] . ' AS ' . strtolower($tmpKey);
				} else {
					$columns[] = $val;
				}
				
			} else {// 有别名
				$tmpKey = strtoupper($key);
				if (isset($this->expr[$tmpKey])) {// 属内部表达式, 指定列名
					$columns[] = $this->expr[$tmpKey] . ' AS ' . $val;
				}
			}
		}
		
		return $toString ? implode(', ', $columns) : null;
	}

	protected function where($cond)
	{
		
	}

	protected function group()
	{
		
	}

	protected function order()
	{
		
	}

	/**
	 * 生成limit语句
	 * 
	 * @param array $page 分页参数
	 *   size int 每次获取数量
	 *   offset int 起始下标
	 * @return string 
	 */
	protected function limit($page)
	{
		if (!is_array($page) || empty($page)) {
			return false;
		}

		if (!isset($page['size'])) {
			return false;			
		}

		if (isset($page['offset'])) {
			return "LIMIT {$page['offset']}, {$page['size']}";
		} else {
			return "LIMIT {$page['size']}";
		}
	}
	
	/**
	 * 生成SQL
	 * 
	 * @param string $column 列
	 * @param string $from 表
	 * @param string $where 条件
	 * @param string $order 排序
	 * @param string $limit 分页
	 */
	protected function sql($column, $from, $where = null, $group = null, $order = null, $limit = null)
	{
		$sql = "SELECT {$column} FROM {$from} {$where} {$group} {$order} {$limit}";
		return $sql;
	}
	
	/**
	 * 插入数据(单条/多条)
	 * 
	 * @param Object $db 数据库对象
	 * @param string $table 表名
	 * @param array $values 数据
	 * @return void 
	 */
	public static function inserts($db, $table, $values) {
		if (!is_array($values) || empty($values)) {
			return false;
		}
		
		// 列名列表
		$fields = null;
		// 是否为一维数组
		$one = false;
		foreach ($values as $key => $item) {
			if (is_array($item)) {
				//获取列名
				$fields = array_keys($values[0]);
				break;
			} else {
				// 获取列名
				$fields = array_keys($values);

				$one = true;
				break;
			}
		}
		
		// 生成列名语句
		$tmpFields = array();
		foreach ($fields as $key => $value) {
			$tmpFields[] = "`{$value}`";
		}
		$fieldsString = implode(',', $tmpFields);
		
		// 生成values语句
		$tmpValues = array();
		$valuesString = null;
		if ($one) {
			foreach ($values as $key => $value) {
				if (is_null($value)) {
					$tmpValues[] = "NULL";
				}elseif (is_string($value)) {
					$tmpValues[] = "'{$value}'";	
				} else {
					$tmpValues[] = $value;
				}	
			}		
			$valuesString = '(' . implode(',', $tmpValues). ')';
		} else {
			$fields = array_keys($values[0]);

			foreach ($values as $key => $item) {
				if (is_array($item) && !empty($item)) {
					foreach ($item as $ikey => $ivalue) {
						if (is_null($ivalue)) {
							$values[$key][$ikey] = "NULL";
						} elseif (is_string($ivalue)) {
							$values[$key][$ikey] = "'{$ivalue}'";
						} else {
							$values[$key][$ikey] = $ivalue;
						}
					}
					$tmpValues[] = "(" . implode(',', $values[$key]) . ")";
				}
			}
			$valuesString = implode(',', $tmpValues);
		}

		$sql = "INSERT INTO {$table} ($fieldsString) VALUES {$valuesString}";
		
		return $db->query($sql);
	}
	
	/**
	 * 更新数据
	 * 
	 * @param Object $db 数据库对象
	 * @param string $table 表名
	 * @param array $data 数据
	 * @param array $cond 条件
	 * @param array $limit 条数限制
	 * @return void 
	 */
	public static function updates($db, $table, $data, $cond = null, $limit = null)
	{
		if (!is_array($data) || empty($data)) {
			return false;
		}
		
		$set = array();
		foreach ($data as $tField => $tValue) {
			$field = "`{$tField}`";
			if (is_null($tValue)) {
				$set[] = "{$field} = NULL";
			}elseif (is_string($tValue)) {
				$set[] = "{$field} = '{$tValue}'";
			} else {
				$set[] = "{$field} = {$tValue}";
			}
		}
		$setString = implode(',', $set);

		$where = $this->where($cond);
		$where ? $where = 'WHERE ' . $where : null;
		$limit = $this->limit($limit);
		$sql = "UPDATE {$table} SET {$setString} {$where} {$limit}";

		return $db->query($sql);	
	}
	
	/**
	 * 删除数据
	 * 
	 * @param Object $db 数据库对象
	 * @param string $table 表名
	 * @param array $cond 条件
	 * @param array $limit 条数限制
	 * @return void 
	 */
	public static function deletes($db, $table, $cond, $limit = null)
	{
		$where = $this->where($cond);
		$where ? $where = 'WHERE ' . $where : null;
		$limit = $this->limit($limit);
		$sql = "DELETE FROM {$table} {$where} {$limit}";

		return $db->query($sql);
	} 
	
	/**
	 * 从文件中导入数据(使用load data infile)
	 * 
	 * @param Object $db 数据库对象
	 * @param string $table 表名
	 * @param string $filename 数据文件名(目前是CSV格式, 其它有时间再改)
	 * @param string $cols 列名
	 * @param bool $isLocal 文件是否在本地
	 * @return bool
	 */
	public static function importByFile($db, $table, $filename, $cols, $isLocal = true)
	{
		$local = $isLocal ? 'LOCAL' : '';

		$sql = 'LOAD DATA ' . $local . ' INFILE "' . $filename . '"
    			INTO TABLE ' . $table . ' 
    			FIELDS TERMINATED BY "," ENCLOSED BY "" 
    			LINES TERMINATED BY "\n" STARTING BY "" (' . $cols . ')';
		return $db->query($sql);
	}

	/**
	 * 统计数组中指定列对应的值, 出现的次数(tmp)
	 *
	 * @param array $data
	 * @param string $colStr
	 * @return array
	 */
	public function iarray_count_values($data, $fieldName)
	{
		if (!is_array($data) || empty($data)) {
			return array();
		}

		$count = array();
		if (is_array($data) && !empty($data)) {
			foreach ($data as $row) {
				$key = strval($row[$fieldName]);
				if (!array_key_exists($key, $count)) {
					$count[$key] = 1;
				} else {
					$count[$key]++;
				}
			}
		}

		return $count;
	}
	
	/**
	 * 获取默认的数据库对象
	 *
	 * @param mixed $args
	 * @return Object
	 *
	 */
	public function getDefaultDb($args = null)
	{
		return Factory::getDb($args);
	}
}
